﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;

using alib.Debugging;
using alib.String;
using alib.Enumerable;
using alib.Collections;
using alib.Collections.ReadOnly;
using alib.Dictionary;
using alib.BitArray;
using alib.Memory;

namespace agree.transfer.old
{
	static class _xts_ext
	{
		public static TransferRelMode trm(TfsSlot ts, TransferGrammar tg) { return new TransferRelMode(tg, ts.tfs.GetIx1RmGgix(ts.ix1)); }
		public static TaggedRelMode tagged_rel_mode(TfsSlot ts) { return ts.tfs.GetIx1RmGgix(ts.ix1); }
		public static RelMode RelMode(TfsSlot ts) { return tagged_rel_mode(ts).rm; }
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[DebuggerDisplay("{ToString(),nq}")]
	public struct RootNodeData
	{
		public RootNodeData(TaggedRelMode tgrm, Edge e)
		{
			this.tgrm = tgrm;
			this.e = e;
		}
		public TaggedRelMode tgrm;
		public Edge e;
		public override String ToString()
		{
			return String.Format("{0} {1}", tgrm.ToString(), e.ToString(tgrm.Grammar.ftm, true));
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	[StructLayout(LayoutKind.Explicit)]
	public struct TaggedRelMode : IEquatable<TaggedRelMode>, IComparable<TaggedRelMode>
	{
		public TaggedRelMode(int ggix, RelMode rm, int tag)
			: this()
		{
#if GGIX
			if ((uint)ggix >= Grammars.Count || Grammars.arr[ggix].g == null)
				throw new Exception();
#endif
			this.b1 = (byte)((ggix & 0xF) | (tag << 4));
			this.rm = rm;
		}
		public TaggedRelMode(int ggix, RelMode rm)
			: this(ggix, rm, 0)
		{
		}

		[FieldOffset(0), DebuggerBrowsable(DebuggerBrowsableState.Never)]
		ushort _internal;
		[FieldOffset(0), DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public RelMode rm;
		[FieldOffset(1), DebuggerBrowsable(DebuggerBrowsableState.Never)]
		byte b1;

		public int grm_idx { get { return b1 & 0xF; } }

		public int Tag
		{
			get { return b1 >> 4; }
			set { b1 = (byte)((value << 4) | (b1 & 0xF)); }
		}

		public bool IsSource { get { return (rm & RelMode.Source) != 0; } }
		public bool IsTarget { get { return (rm & RelMode.Target) != 0; } }
		public bool IsInRel { get { return (rm & RelMode.In) != 0; } }
		public bool IsOutRel { get { return (rm & RelMode.Out) != 0; } }

		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public Grammar Grammar
		{
			get
			{
				int grm_idx = b1 & 0xF;
				Grammar g = Grammar.GetGrammar(grm_idx);
				if (g == null || g.grm_idx != grm_idx)
					return null;
				return g;
			}
		}

		public FeatMgr ftm
		{
			get
			{
				var g = this.Grammar;
				return g == null ? null : g.ftm;
			}
		}

		public static bool operator ==(TaggedRelMode a, TaggedRelMode b) { return a._internal == b._internal; }

		public static bool operator !=(TaggedRelMode a, TaggedRelMode b) { return a._internal != b._internal; }

		public bool Equals(TaggedRelMode other) { return this._internal == other._internal; }

		public override bool Equals(object obj) { return obj is TaggedRelMode && this._internal == ((TaggedRelMode)obj)._internal; }

		public override int GetHashCode() { return _internal; }

		public override string ToString()
		{
			Grammar g = this.Grammar;
			String s_grm = g == null ? "(g==null)" : g.Name;
			String s = String.Format("{0,7} {1,4} {2,6}",
				s_grm,
				IsSource ? "Src" : IsTarget ? "Tgt" : "",
				IsInRel ? "In" : IsOutRel ? "Out" : "None");
			return s;
		}

		public int CompareTo(TaggedRelMode other)
		{
			int d, i0 = (int)this.rm & 9, i1 = (int)other.rm & 9;
			if (((i0 | i1) & 8) != 0)
			{
				i0 ^= (i0 >> 3);
				i1 ^= (i1 >> 3);
			}
			else
			{
				i0 ^= this.grm_idx;
				i1 ^= other.grm_idx;
			}
			if ((d = i0 - i1) != 0)
				return d;
			d = this.grm_idx - other.grm_idx;
			if (d != 0)
				return d;
			return this.Tag - other.Tag;
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class TransferMrs : ArrayTfs, IIdentity
	{
#if OLDMRS
		public TransferMrs(IIdentity prv, Mrs.Mrs mrs)
			: base(prv, default(ArrayTfs))
		{
		}

#else
		public TransferMrs(IRtParent parent)
			: base(parent, default(_atfs_base))
		{
		}
#endif
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class TransferTfs : MultiRootTfs
	{
		public TransferTfs(IRtParent parent, TransferGrammar tg, TfsBuilder.Xdl xdlb)
			: base(parent, xdlb)
		{
			this.tg = tg;
		}

		public TransferGrammar tg;
		public TransferGrammar TransferGrammar { get { return tg; } }

		public TransferRelMode GetSlotTrm(int ix1)
		{
			return new TransferRelMode(tg, entries[ix1 - 1].tgrm);
		}
	};

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public class SrcTgtRelsTfs : TransferTfs
	{
		public SrcTgtRelsTfs(IRtParent parent, SrcTgtGrammar tg)
			: base(parent, tg, null)
		{
		}

		public new SrcTgtGrammar TransferGrammar { get { return (SrcTgtGrammar)base.tg; } }

		public IList<TfsSlot> SourceInRels { get { return null; } }
		public IList<TfsSlot> SourceOutRels { get { return null; } }
		public IList<TfsSlot> TargetInRels { get { return null; } }
		public IList<TfsSlot> TargetOutRels { get { return null; } }
	};
}
